package com.ra.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ra.exception.BizException;
import com.ra.mapper.RoleMapper;
import com.ra.mapper.RoleMenuMapper;
import com.ra.pojo.Menu;
import com.ra.mapper.MenuMapper;
import com.ra.pojo.RespBean;
import com.ra.pojo.RoleMenu;
import com.ra.pojo.dto.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ra.service.RedisService;
import com.ra.utils.BeanCopyUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ra.service.IMenuService;
import java.util.*;
import java.util.stream.Collectors;

import static com.ra.constant.CommonConstant.TRUE;
import static java.util.stream.Collectors.groupingByConcurrent;
import static java.util.stream.Collectors.toList;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 今晚几点睡_Ada
 * @since 2023-03-09
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IMenuService {

    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Override
    public RespBean<?> getMenusByUserId() {
        UserDetailsDTO userDetailsDTO = (UserDetailsDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
      /*  List<Menu> menus =  (List<Menu>) redisService.get("menu_" + userDetailsDTO.getUserInfoId());

        if (CollectionUtils.isEmpty(menus)){
             menus=  menuMapper.getMenusByUserId(userDetailsDTO.getUserInfoId());
             redisService.set("menu_"+userDetailsDTO.getUserInfoId(),menus);
        }
*/
       List<Menu> menus = menuMapper.getMenusByUserId(userDetailsDTO.getUserInfoId());
        //父菜单
        List<Menu> parents = menus.stream()
                .filter(item -> Objects.isNull(item.getParentId()))
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .collect(toList());

        //子菜单
        Map<Integer, List<Menu>> childrens = menus.stream()
                .filter(item -> item.getParentId() != null)
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .collect(groupingByConcurrent(Menu::getParentId));

         List<UserMenuDTO> lists = parents.stream().map(item -> {
            UserMenuDTO userMenuDTO = new UserMenuDTO();
            List<UserMenuDTO> list = new ArrayList<>();
            List<Menu> children = childrens.get(item.getId());
            if (CollectionUtils.isNotEmpty(children)) {
                userMenuDTO = BeanCopyUtil.copyObject(item, UserMenuDTO.class);
                list = children.stream()
                        .sorted(Comparator.comparing(Menu::getOrderNum))
                        .map(menu -> {
                            UserMenuDTO dto = BeanCopyUtil.copyObject(menu, UserMenuDTO.class);
                            dto.setHidden(menu.getIsHidden().equals(TRUE));
                            return dto;
                        })
                        .collect(toList());
            } else {
                userMenuDTO.setPath(item.getPath());
                userMenuDTO.setComponent("Layout");
                list.add(UserMenuDTO.builder()
                        .path("")
                        .name(item.getName())
                        .icon(item.getIcon())
                        .component(item.getComponent())
                        .build());
            }
            userMenuDTO.setHidden(item.getIsHidden().equals(TRUE));
            userMenuDTO.setChildren(list);
            return userMenuDTO;
        }).collect(toList());

        return RespBean.success(lists);
    }

    @Override
    public List<MenuDTO> listMenus(ConditionDTO conditionDTO) {
        List<Menu> menus = menuMapper.selectList(new LambdaQueryWrapper<Menu>()
                .like(StringUtils.isNotBlank(conditionDTO.getKeywords()), Menu::getName, conditionDTO.getKeywords()));

        //父菜单
        List<Menu> parents = menus.stream()
                .filter(item -> item.getParentId() == null)
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .collect(toList());

        //子菜单
        Map<Integer, List<Menu>> childrens = menus.stream()
                .filter(item -> item.getParentId() != null)
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .collect(groupingByConcurrent(Menu::getParentId));

        List<MenuDTO> list = parents.stream().map(item -> {
            MenuDTO menuDTO = BeanCopyUtil.copyObject(item, MenuDTO.class);
            List<MenuDTO> menuList = BeanCopyUtil.copyList(childrens.get(item.getId()), MenuDTO.class).stream()
                    .sorted(Comparator.comparing(MenuDTO::getOrderNum, Comparator.nullsFirst(Comparator.naturalOrder())))
                    .collect(toList());

            menuDTO.setChildren(menuList);
            childrens.remove(item.getId());
            return menuDTO;
        }).sorted(Comparator.comparing(MenuDTO::getOrderNum, Comparator.nullsFirst(Comparator.naturalOrder())))

                .collect(toList());
        //如果子菜单Map里还有没移除完的
        if (CollectionUtils.isNotEmpty(childrens)) {
            List<Menu> childrenList = new ArrayList<>();
            childrens.values().forEach(childrenList::addAll);
            //转为list之后排序
            List<MenuDTO> childrenDTOList = childrenList.stream()
                    .map(item -> BeanCopyUtil.copyObject(item, MenuDTO.class))
                    .sorted(Comparator.comparing(MenuDTO::getOrderNum, Comparator.nullsFirst(Comparator.naturalOrder())))
                    .collect(Collectors.toList());
            //全部添加到list
            list.addAll(childrenDTOList);
        }

        return list;
    }

    @Transactional
    @Override
    public void saveOrUpdateMenu(MenuDTO menuDTO) {
        Menu menu = BeanCopyUtil.copyObject(menuDTO, Menu.class);
        System.out.println("menu = " + menu);
        this.saveOrUpdate(menu);
    }

    @Override
    public void updateMenuIsHidden(IsHidden isHidden) {
        Menu menu = BeanCopyUtil.copyObject(isHidden, Menu.class);
        System.out.println("menu = " + menu);
        menuMapper.updateById(menu);
    }
    @SneakyThrows
    @Override
    public void deleteMenu(Integer menuId) {
        Integer count = roleMenuMapper.selectCount(new LambdaQueryWrapper<RoleMenu>()
                .eq(RoleMenu::getMenuId, menuId));
        if (count > 0) {
            throw new BizException("菜单下有角色关联");
        }
        //查询Menu表中所有parentId等于menuId的记录，并且只查询id字段
        List<Menu> menus = menuMapper.selectList(new LambdaQueryWrapper<Menu>()
                .select(Menu::getId)
                .eq(Menu::getParentId, menuId));

        System.out.println("menus = " + menus);
        List<Integer> menuIds = menus.stream()
                .map(Menu::getId)
                .collect(toList());
        menuIds.add(menuId);
        System.out.println("menuId = " + menuIds);
          menuMapper.deleteBatchIds(menuIds);
    }

    @Override
    public List<LabelOptionDTO> listMenuOptions() {
        List<Menu> menus = menuMapper.selectList(new LambdaQueryWrapper<Menu>()
                .select(Menu::getId, Menu::getName, Menu::getParentId, Menu::getOrderNum));
        //父菜单
        List<Menu> parents = menus.stream()
                .filter(item -> Objects.isNull(item.getParentId()))
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .collect(toList());

        //子菜单
        Map<Integer, List<Menu>> childrens = menus.stream()
                .filter(item -> Objects.nonNull(item.getParentId()))
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .collect(groupingByConcurrent(Menu::getParentId));

        List<LabelOptionDTO> labelOptionDTOS = parents.stream().map(item -> {
            List<LabelOptionDTO> list = new ArrayList<>();
            List<Menu> children = childrens.get(item.getId());
            if (CollectionUtils.isNotEmpty(children)) {
                list = children.stream()
                        .sorted(Comparator.comparing(Menu::getOrderNum))
                        .map(menu -> LabelOptionDTO.builder()
                                .id(menu.getId())
                                .name(menu.getName())
                                .build())
                        .collect(toList());
            }
            return LabelOptionDTO.builder()
                    .id(item.getId())
                    .name(item.getName())
                    .subItem(list)
                    .build();
        }).collect(toList());
        return labelOptionDTOS;

    }


}
